var DomReady = window.DomReady = {},
    userAgent = navigator.userAgent.toLowerCase(),
    browser = {
      version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
      safari: /webkit/.test(userAgent),
      opera: /opera/.test(userAgent),
      msie: (/msie/.test(userAgent)) && (!/opera/.test( userAgent )),
      mozilla: (/mozilla/.test(userAgent)) && (!/(compatible|webkit)/.test(userAgent))
    },
    readyBound = false,
    isReady = false,
    readyList = [];


function domReady() {
  // Make sure that the DOM is not already loaded
  if(!isReady) {
    // Remember that the DOM is ready
    isReady = true;

    if(readyList) {
      var length = readyList.length;
      for(var fn = 0; fn < length; fn++) {
        readyList[fn].call(window, []);
      }

      readyList = [];
    }
  }
};

// From Simon Willison. A safe way to fire onload w/o screwing up everyone else.
function addLoadEvent(func) {
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  }
  else {
    window.onload = function() {
      if (oldonload) {
        oldonload();
      }
      func();
    }
  }
};

// does the heavy work of working through the browsers idiosyncracies (let's call them that) to hook onload.
function bindReady() {
  if(readyBound) {
    return;
  }

  readyBound = true;

  // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
  if (document.addEventListener && !browser.opera) {
    // Use the handy event callback
    document.addEventListener("DOMContentLoaded", domReady, false);
  }

  // If IE is used and is not in a frame
  // Continually check to see if the document is ready
  if (browser.msie && window == top) (function() {
    if (isReady) return;
    try {
      // If IE is used, use the trick by Diego Perini
      // http://javascript.nwbox.com/IEContentLoaded/
      document.documentElement.doScroll("left");
    }
    catch(error) {
      setTimeout(arguments.callee, 0);
      return;
    }
    // and execute any waiting functions
    domReady();
  })();

  if(browser.opera) {
    document.addEventListener( "DOMContentLoaded", function () {
      if (isReady) return;
      for (var i = 0; i < document.styleSheets.length; i++)
      if (document.styleSheets[i].disabled) {
        setTimeout( arguments.callee, 0 );
        return;
      }
      // and execute any waiting functions
      domReady();
    }, false);
  }

  if(browser.safari) {
    var numStyles;
    (function(){
      if (isReady) return;

      if (document.readyState != "loaded" && document.readyState != "complete") {
        setTimeout( arguments.callee, 0 );
        return;
      }

      if (numStyles === undefined) {
        var links = document.getElementsByTagName("link");
        for (var i=0; i < links.length; i++) {
          if(links[i].getAttribute('rel') == 'stylesheet') {
            numStyles++;
          }
        }

        var styles = document.getElementsByTagName("style");
        numStyles += styles.length;
      }

      if (document.styleSheets.length != numStyles) {
        setTimeout( arguments.callee, 0 );
        return;
      }

      // and execute any waiting functions
      domReady();
    })();
  }

  // A fallback to window.onload, that will always work
  addLoadEvent(domReady);
};

// This is the public function that people can use to hook up ready.
DomReady.ready = function(fn, args) {
  // Attach the listeners
  bindReady();

  // If the DOM is already ready
  if (isReady) {
    // Execute the function immediately
    fn.call(window, []);
  }
  else {
    // Add the function to the wait list
    readyList.push( function() { return fn.call(window, []); } );
  }
};

NinjsDOM = function() {
	this.cached_selectors = {};
};

// This is the public function that people can use to hook up ready.
NinjsDOM.prototype.ready = function(fn, args) {
	// Attach the listeners
	bindReady();

	// If the DOM is already ready
	if (isReady) {
		// Execute the function immediately
		fn.call(window, args || []);
	}
	else {
		// Add the function to the wait list
		readyList.push( function() { return fn.call(window, args || []); } );
	}
};

bindReady();